#ifndef _XX_YY_BMOCK_CHECK_HPP
#define _XX_YY_BMOCK_CHECK_HPP

#ifdef BMOCK_USE_MOCKS
#include "detail/bmock_test_mode_control.hpp"
#include "bmock_expand_arg.hpp"
#include <vector>
#include "detail/bmock_logfile.hpp"
#include <string>
#endif
#include <boost/preprocessor/facilities/expand.hpp> 
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/current_function.hpp>

#define __BMOCK_CREATE_MOCK_C(C,FN)\
	C->define_mock(BOOST_PP_STRINGIZE(FN));

#define BMOCK_CREATE_MOCK(FN)\
	__BMOCK_CREATE_MOCK_C(bmock::test_mode_control::get_instance(),FN)

#define __CHECK_MOCK(C)\
	(C != NULL) && (C->mock_defined(bmock::func_info(BOOST_CURRENT_FUNCTION,__FUNCTION__).get_func_name())||C->exact_mock_defined(bmock::func_info(BOOST_CURRENT_FUNCTION,__FUNCTION__).get_func_sig()))

#ifndef BMOCK_DISABLE_WARNINGS
#define __BMOCK_COMPARE_ARGS_TO_FUNC_SIG(C,ARGS,AC,FI,LOC) \
	{ \
	C->compare_args_to_func_sig(std::vector<bmock::argument>(ARGS, ARGS + AC), FI.get_args_types(), LOC);\
	}
#else	
#define __BMOCK_COMPARE_ARGS_TO_FUNC_SIG(C,ARGS,AC,FI,LOC)  BOOST_PP_EMPTY()
#endif

#define __LOG_FUNCTION_INFO(FI, NUM_OF_TUBS) \
	{ \
	bmock::bmock_mutex::instance()->lock(); \
	bmock::bmock_logfile::instance()->add_to_log(std::string(NUM_OF_TUBS, '\t') + FI.get_func_sig()); \
	bmock::bmock_mutex::instance()->unlock(); \
	}\

#define __CHECK_COMMON(C,AC,AL)\
	bmock::location __current$$loc__(__FILE__,__LINE__);\
	bmock::func_info fi(BOOST_CURRENT_FUNCTION,__FUNCTION__);\
	__LOG_FUNCTION_INFO(fi, 1); \
	__BMOCK_ARG_LIST(AC,AL)\
	__BMOCK_COMPARE_ARGS_TO_FUNC_SIG(C,args_,AC,fi,__current$$loc__)\
	C->check(bmock::func_spec(fi.get_return_type(),fi.get_func_name(),__current$$loc__),bmock::arg_list(args_,AC));

#define __VOID_CHECK(C,AC,AL)\
	{\
	__CHECK_COMMON(C,AC,AL); \
	C->return_void(__current$$loc__);\
	return;\
	} \

#define __NOT_VOID_CHECK(C,AC,AL)\
	{\
	__CHECK_COMMON(C,AC,AL); \
	bmock::bmock_any ba = C->get_new_result();\
	return ba;\
	} \
	
#ifdef BMOCK_USE_MOCKS
#define __MOCK_VOID_C(C,AC,AL)\
	if (__CHECK_MOCK(C)) { \
	__VOID_CHECK(C,AC,AL) \
	} \
	{ \
	__LOG_FUNCTION_INFO(bmock::func_info(BOOST_CURRENT_FUNCTION,__FUNCTION__), 2); \
	}\

#define __MOCK_C(C,AC,AL)\
	if (__CHECK_MOCK(C)) {\
	__NOT_VOID_CHECK(C,AC,AL) \
	} \
	{ \
		__LOG_FUNCTION_INFO(bmock::func_info(BOOST_CURRENT_FUNCTION,__FUNCTION__), 2); \
	}
#else
#define __MOCK_VOID_C(C,AC,AL) BOOST_PP_EMPTY()
#define __MOCK_C(C,AC,AL) BOOST_PP_EMPTY()
#endif

#define __STATIC_MOCK_VOID_C(C,AC,AL)\
	__VOID_CHECK(C,AC,AL) 

#define __STATIC_MOCK_C(C,AC,AL)\
	__NOT_VOID_CHECK(C,AC,AL) 


#define MOCK_VOID(AC,AL)\
	{\
	__MOCK_VOID_C(bmock::test_mode_control::get_instance(),AC,AL)\
	}

#define MOCK(AC,AL)\
	{\
	__MOCK_C(bmock::test_mode_control::get_instance(),AC,AL)\
	}

#define STATIC_MOCK_VOID(AC,AL)\
	{\
	__STATIC_MOCK_VOID_C(bmock::test_mode_control::get_instance(),AC,AL)\
	}

#define STATIC_MOCK(AC,AL)\
	{\
	__STATIC_MOCK_C(bmock::test_mode_control::get_instance(),AC,AL)\
	}

#endif
